﻿using Google.Apis.Drive.v2.Data;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace WotModSync
{
    public class CompareEngine
    {
        private List<FileInfo> localFiles;
        private List<Google.Apis.Drive.v2.Data.File> remoteFiles;
        private bool remote;
        private string wotDirectory;

        public CompareEngine(List<FileInfo> localFiles, List<Google.Apis.Drive.v2.Data.File> remoteFiles, bool remote, string wotDirectory)
        {
            this.localFiles = localFiles;
            this.remoteFiles = remoteFiles;
            this.remote = remote;
            this.wotDirectory = wotDirectory;
        }

        public List<CompareResult> Compare()
        {
            if (!remote)
                return CompareLocal();
            return CompareRemote();
        }

        public List<CompareResult> CompareLocal()
        {

            var list = new List<CompareResult>();
            //Update + Add
            foreach (Google.Apis.Drive.v2.Data.File f in remoteFiles)
            {
                string sourcePath = GoogleDrive.GetSourcePathValue(f);
                if (string.IsNullOrEmpty(sourcePath)) continue;
                string localPath = Path.Combine(wotDirectory, sourcePath);

                var fileInfo = new FileInfo(localPath);

                if (fileInfo.Exists)
                {
                    //Update ?
                    if (fileInfo.Length != f.FileSize)
                    {
                        list.Add(new CompareResult()
                        {
                            State = ResultState.Update,
                            RemoteFile = f,
                            LocalFile = fileInfo
                        });

                    }
                    else
                    {
                        string checkSumLocal = BitConverter.ToString(computeMd5(fileInfo.FullName)).Replace("-", "").ToLower();

                        if (f.Md5Checksum != checkSumLocal)
                        {
                            list.Add(new CompareResult()
                            {
                                State = ResultState.Update,
                                RemoteFile = f,
                                LocalFile = fileInfo
                            });
                        }
                    }


                    var delFile = localFiles.FirstOrDefault(fi => fi.FullName == fileInfo.FullName);

                    if (!localFiles.Remove(delFile))
                    {
                        throw new ArgumentException("");
                    };
                }
                else
                {
                    //Add
                    list.Add(new CompareResult()
                    {
                        State = ResultState.Add,
                        RemoteFile = f,
                        LocalFile = fileInfo
                    });

                }
            }

            //Delete
            foreach (FileInfo file in localFiles)
            {
                if (file.Exists)
                {
                    list.Add(new CompareResult()
                    {
                        State = ResultState.Delete,
                        LocalFile = file
                    });
                }
            }

            return list;

        }

        public List<CompareResult> CompareRemote()
        {
            var list = new List<CompareResult>();
            foreach (FileInfo fileInfo in localFiles)
            {
                string sourcePath = fileInfo.FullName.Replace(wotDirectory, "").Trim('\\');

                var f = remoteFiles.FirstOrDefault(r => r.Properties.Any(pr => pr.Key == GoogleDrive.PropertySourcePath && pr.Value == PathUtils.ReplaceBackslash(sourcePath)));

                if (f == null)
                {
                    //Add
                    list.Add(new CompareResult()
                    {
                        State = ResultState.Add,
                        LocalFile = fileInfo
                    });

                }
                else
                {
                    if (f.FileSize != fileInfo.Length)
                    {
                        list.Add(new CompareResult()
                        {
                            State = ResultState.Update,
                            RemoteFile = f,
                            LocalFile = fileInfo
                        });
                    }
                    else
                    {

                        string checkSumLocal = BitConverter.ToString(computeMd5(fileInfo.FullName)).Replace("-", "").ToLower();

                        if (f.Md5Checksum != checkSumLocal)
                        {
                            list.Add(new CompareResult()
                            {
                                State = ResultState.Update,
                                RemoteFile = f,
                                LocalFile = fileInfo
                            });
                        }
                    }

                    remoteFiles.Remove(f);

                }

            }



            //Delete
            foreach (Google.Apis.Drive.v2.Data.File f in remoteFiles)
            {
              
                    list.Add(new CompareResult()
                    {
                        State = ResultState.Delete,
                        RemoteFile = f
                    });
            }

            return list;

        }

        private byte[] computeMd5(string filename)
        {
            using (var md5 = MD5.Create())
            {
                using (var stream = System.IO.File.OpenRead(filename))
                {
                    return md5.ComputeHash(stream);
                }
            }
        }
    }

    public enum ResultState { Add, Update, Delete }

    public class CompareResult
    {


        public ResultState State { get; set; }

        public FileInfo LocalFile { get; set; }

        public Google.Apis.Drive.v2.Data.File RemoteFile { get; set; }

    }
}
